package pl.edu.pw.ee.buildcity.gg;

import org.apache.log4j.Logger;
import pl.edu.pw.ee.buildcity.commons.exceptions.BuildCityRuntimeException;
import pl.edu.pw.ee.buildcity.gg.commands.Command;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.trimToEmpty;

/**
 * @author Mateusz
 * @since 2010-02-13
 */
public class GGCommandsHandler {

	private static final Logger log = Logger.getLogger(GGCommandsHandler.class);

	//Injected by Spring map of GG commands
	private final Map<String, Command> commands;

	public GGCommandsHandler(Map<String, Command> commands) {
		this.commands = commands;
	}

	/**
	 * Gets message in format like: <code>command: parameter1 parameter2</code>, tries to
	 * find appropriate command implementation and calls it's {@link Command#execute(java.util.List)}
	 * <p>
	 * Example command: <code>build: myJob</code> will fire job which would run quartz job with build definition 'myJob'.
	 * </p>
	 * <p>
	 * This method implementation uses <b>Command</b> design pattern
	 * </p>
	 *
	 * @param incomingMessageBody raw message sent from client
	 * @return message return by {@link Command} implementation
	 * @throws BuildCityRuntimeException when
	 */
	public String processMessage(String incomingMessageBody) {

		Command command = null;
		List<String> commandParamsList = null;

		try {
			String[] commandAndParams = incomingMessageBody.split(":");
			String commandType = commandAndParams[0];

			//Get params
			String rawCommandParams = commandAndParams[1]; // like 'param1, param2, param3'
			commandParamsList = extractParamsIntoList(rawCommandParams);

			command = findCommand(commandType); //Throws runtime exception when command not found

		} catch (BuildCityRuntimeException e) {
			log.error(e.getMessage());
			throw e;
		} catch (Exception e) {
			log.error("Error while parsing incoming message: " + incomingMessageBody, e);
			throw new BuildCityRuntimeException("Wrong command format. Example: '<command>: [parameter1],[parameter2],...[parameterN]'");
		}

		log.debug("Running " + command + " command with parameters: " + commandParamsList);
		return command.execute(commandParamsList);
	}

	private List<String> extractParamsIntoList(String rawCommandParams) {
		if (isBlank(rawCommandParams)) {
			return Collections.emptyList();
		}
		rawCommandParams = trimToEmpty(rawCommandParams);
		return Arrays.asList(rawCommandParams.split("\\s*,\\s*"));
	}

	private Command findCommand(String commandType) throws BuildCityRuntimeException {
		Command command = commands.get(commandType);
		if (command == null) {
			throw new BuildCityRuntimeException("Unknown command '" + commandType + "'");
		}
		return command;
	}
}